package com.nm;

import com.nm.dto.DivideLendInfo;
import com.nm.dto.MonthPaybackInfo;
import com.nm.dto.SeperateFee;
import com.nm.factory.LenderToolBox;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class App {
    public static void main(String[] args) {
        boolean print = false;//是否打印
        double ben_jin = 10000;//本金
        double fee = 1000;//每一笔成交的手续费
        double qishu = 12;//期数
        double rate = 0.36f;//年化利率APR
        double huanzhang = 0;//还账率
//        int zhouqi = 32;
        int zhouqi = 365 * 2;//周期：天
        int outDay = zhouqi;//放款天数
        int everyDayOut = 50;//每天放款
        double everyMustOut = 20000;//每日固定支出
        LenderToolBox lenderToolBox = new LenderToolBox();
        LocalDate localDate = LocalDate.now();
        int index = 0;
        Map<String, List<DivideLendInfo>> dis = new HashMap<>();
        Map<String, List<MonthPaybackInfo>> mMap = new HashMap<>();

        BigDecimal outSide = new BigDecimal(0);//投入本金总数
        BigDecimal outPrinpal = new BigDecimal(0);//投入本金总数
        BigDecimal inSide = new BigDecimal(0);//收回款项总数
        BigDecimal mustOut = new BigDecimal(0);//固定支出总数
        while (true) {
            index++;
            mustOut = mustOut.add(new BigDecimal(everyMustOut));
            if (index < zhouqi) {
                /**
                 * 放款日期，当天
                 */
                String date = localDate.plusDays(index).format(DateTimeFormatter.ISO_LOCAL_DATE);
                /**
                 * 计算收回
                 */
                BigDecimal thisDayGet = inByDate(mMap, date).multiply(new BigDecimal(1 - huanzhang));
                /**
                 * 其中收回的本金
                 */
                BigDecimal backPrincpal = backPrinpal(mMap, date).multiply(new BigDecimal(1 - huanzhang));
                outPrinpal = outPrinpal.subtract(backPrincpal);

                if (index < outDay){
                    for (int i = 0; i < everyDayOut; i++) {
                        /**
                         * 计算放款的结果
                         */
                        DivideLendInfo divideLendInfo = lenderToolBox.everyMonthSamePayBack(localDate.plusDays(index), false, ben_jin, qishu, rate, fee, 2);
                        boolean decideToOut = true;

                        /**
                         * 存入单子信息
                         */
                        if (thisDayGet.subtract(divideLendInfo.getPrincipal()).compareTo(new BigDecimal(0)) > 0) {
                            /**
                             * 利用收回的钱去贷款
                             */
                            thisDayGet = thisDayGet.subtract(divideLendInfo.getPrincipal());
                        }else {
                            /**
                             * 自己拿钱放
                             */
                            if (outSide.compareTo(new BigDecimal(1000 * 10 * 100)) > 0) {
                                decideToOut = false;
                            }else {
                                outSide = outSide.add(divideLendInfo.getPrincipal());
                            }
                        }
                        if (decideToOut) {
                            /**
                             * 存入还款计划，用于计算还款
                             */
                            for (MonthPaybackInfo info : divideLendInfo.getMonthPaybackInfos()) {
                                List<MonthPaybackInfo> infos = mMap.computeIfAbsent(info.getDatetime(), k -> new LinkedList<>());
                                infos.add(info);
                            }
                            List<DivideLendInfo> divideLendInfos = dis.computeIfAbsent(date, k -> new LinkedList<>());
                            divideLendInfos.add(divideLendInfo);
                            /**
                             * 支出的本金
                             */
                            outPrinpal = outPrinpal.add(divideLendInfo.getPrincipal());
                        }

                    }
                }
                /**
                 * 存入扣除拿去放款的钱，实际收回的钱
                 */
                inSide = inSide.add(thisDayGet);

                /**
                 * 结余
                 */
                double rest = inSide.subtract(outSide).subtract(mustOut).doubleValue();
                /**
                 * 支出
                 */
                double outd = outSide.doubleValue();
                System.out.printf("%d %s 总支出 %,.2f 总收入 %,.2f 营收 %,.2f 百分比 %.6f  固定支出%,.2f 未收回本金%,.2f\n ",index,date,outd, inSide.doubleValue(),rest,rest / outd,mustOut.doubleValue(),outPrinpal.doubleValue());
//                if (rest > 0) {
//                    break;
//                }
                continue;
            }
            break;
        }
    }

    private static BigDecimal inByDate(Map<String, List<MonthPaybackInfo>> dis,String now) {
        BigDecimal in = new BigDecimal(0);
        List<MonthPaybackInfo> monthPaybackInfos = dis.get(now);
        if (monthPaybackInfos == null) {
            return in;
        }
        for (MonthPaybackInfo monthPaybackInfo : monthPaybackInfos) {
//            System.out.printf("+%.2f\t",monthPaybackInfo.getAmountPayback());
            in = in.add(monthPaybackInfo.getAmountPayback());
//            System.out.printf("=%.2f\t",in.doubleValue());
            if (monthPaybackInfo.getSeperateFees() != null && monthPaybackInfo.getSeperateFees().size() > 0) {
                for (SeperateFee fee : monthPaybackInfo.getSeperateFees()) {
//                    System.out.printf("+%.2f\t",fee.getAmount());
                    in = in.add(fee.getAmount());
//                    System.out.printf("=%.2f\t",in.doubleValue());
                }
            }
        }
//        System.out.print("\n");
        return in;
    }

    private static BigDecimal backPrinpal(Map<String, List<MonthPaybackInfo>> dis,String now) {
        BigDecimal in = new BigDecimal(0);
        List<MonthPaybackInfo> monthPaybackInfos = dis.get(now);
        if (monthPaybackInfos == null) {
            return in;
        }
        for (MonthPaybackInfo monthPaybackInfo : monthPaybackInfos) {
//            System.out.printf("+%.2f\t",monthPaybackInfo.getAmountPayback());
            in = in.add(monthPaybackInfo.getPrincipal());
//            System.out.printf("=%.2f\t",in.doubleValue());
        }
//        System.out.print("\n");
        return in;
    }
    private static BigDecimal in(Map<String, List<DivideLendInfo>> dis,String now) {
        BigDecimal in = new BigDecimal(0);
//        System.out.println(dis.size());
        for (Map.Entry<String, List<DivideLendInfo>> entry : dis.entrySet()) {
            String key = entry.getKey();
            List<DivideLendInfo> value = entry.getValue();
//            System.out.println(value.size());
            for (DivideLendInfo info : value) {
                in = infoIn(now, in, info);
            }
        }
        return in;
    }

    private static BigDecimal infoIn(String now, BigDecimal in, DivideLendInfo info) {
        List<MonthPaybackInfo> monthPaybackInfos = info.getMonthPaybackInfos();
        for (MonthPaybackInfo monthPaybackInfo : monthPaybackInfos) {
//                    System.out.printf("%s %.2f", monthPaybackInfo.getDatetime(), monthPaybackInfo.getAmountPayback().doubleValue());
            if (now.equals(monthPaybackInfo.getDatetime())) {
//                        System.out.println("in");
                in = in.add(monthPaybackInfo.getAmountPayback());
                if (monthPaybackInfo.getSeperateFees() != null && monthPaybackInfo.getSeperateFees().size() > 0) {
                    for (SeperateFee fee : monthPaybackInfo.getSeperateFees()) {
                        in = in.add(fee.getAmount());
                    }
                }
                break;
            }
        }
        return in;
    }

    /**
     * 等额本息,每一期，一个月，30天
     * @param print
     * @param ben_jin
     * @param fee
     * @param qishu
     * @param rate
     */
    private static void everyMonthSamePayBack(boolean print, double ben_jin, double fee, double qishu, double rate) {
        double rateOfMonth = rate / 12;//
        double everyMonthPayBack = ben_jin * rateOfMonth * Math.pow(1 + rateOfMonth, qishu) / (Math.pow(1+rateOfMonth, qishu)-1);
        double yinli = everyMonthPayBack * qishu - ben_jin;
        double irr = (yinli + fee)/ ben_jin;
        System.out.printf("本金 %.2f 期数 %.0f 利率(APR) %.6f 利息盈利 %.2f 手续费 %.2f 真实利率(IRR) %.6f\n", ben_jin, qishu, rate,yinli,fee,irr);
        if (print) {
            for (int i = 1; i <= qishu; i++) {
                double currrentInterest = ben_jin * rateOfMonth * (Math.pow(1 + rateOfMonth, qishu) - Math.pow(1 + rateOfMonth, i - 1)) / (Math.pow(1 + rateOfMonth, qishu) - 1);
                System.out.printf("第%d期 %.2f %.2f %.2f\n",i,everyMonthPayBack,currrentInterest,everyMonthPayBack - currrentInterest);
            }
        }
    }

}
